using System;
using System.Data;
using System.IO;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.ServiceObjects;

namespace Oracle.ManagedDataAccess.Types
{
	public sealed class OracleXmlStream : Stream, ICloneable
	{
		private bool m_bClosed;

		private long m_length;

		private long m_position;

		private OracleConnection m_connection;

		private OracleXmlType m_xmlType;

		internal OracleXmlStreamImpl m_xmlStreamImpl;

		private object lockXmlStream = new object();

		public override bool CanRead
		{
			get
			{
				if (m_bClosed)
				{
					return false;
				}
				return true;
			}
		}

		public override bool CanSeek
		{
			get
			{
				if (m_bClosed)
				{
					return false;
				}
				return true;
			}
		}

		public override bool CanWrite => false;

		public OracleConnection Connection
		{
			get
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				return m_connection;
			}
		}

		public override long Length
		{
			get
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				try
				{
					return m_xmlStreamImpl.GetLength();
				}
				catch (Exception ex)
				{
					OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.get_Length, ex);
					throw;
				}
			}
		}

		public string Value
		{
			get
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				try
				{
					return m_xmlStreamImpl.GetValue();
				}
				catch (Exception ex)
				{
					OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.get_Value, ex);
					throw;
				}
			}
		}

		public override long Position
		{
			get
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				return m_position;
			}
			set
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				m_position = value;
			}
		}

		public OracleXmlStream(OracleXmlType xmlType)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.ctor);
			}
			if (xmlType == null)
			{
				throw new ArgumentNullException("xmlType");
			}
			m_xmlType = xmlType;
			OracleConnection connection = xmlType.m_connection;
			if (connection == null || connection.m_connectionState != ConnectionState.Open)
			{
				GC.SuppressFinalize(this);
				throw new InvalidOperationException();
			}
			if (connection.m_connectionState != ConnectionState.Open)
			{
				GC.SuppressFinalize(this);
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_CLOSED));
			}
			try
			{
				m_connection = xmlType.m_connection;
				m_xmlStreamImpl = new OracleXmlStreamImpl(m_connection.m_oracleConnectionImpl, xmlType.m_xmlTypeImpl);
				if (m_connection.m_oracleConnectionImpl != null)
				{
					m_connection.m_oracleConnectionImpl.RegisterForConnectionClose(this);
				}
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.ctor, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.ctor);
				}
			}
		}

		private void Initialize(OracleXmlType xmlType)
		{
		}

		public object Clone()
		{
			if (m_bClosed)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
			}
			return new OracleXmlStream(m_xmlType)
			{
				m_position = m_position
			};
		}

		public override void Close()
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.XML, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Close, "OracleXmlStream::Close");
			}
			if (m_bClosed)
			{
				return;
			}
			lock (lockXmlStream)
			{
				try
				{
					if (!m_bClosed)
					{
						m_xmlStreamImpl.Dispose();
						m_position = 0L;
						m_length = 0L;
					}
				}
				catch (Exception ex)
				{
					if (ProviderConfig.m_bTraceLevelPublic)
					{
						Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Close, ex.ToString());
					}
				}
				finally
				{
					m_bClosed = true;
					if (m_connection != null && m_connection.m_oracleConnectionImpl != null)
					{
						m_connection.m_oracleConnectionImpl.DeregisterForConnectionClose(this);
					}
					m_connection = null;
					if (ProviderConfig.m_bTraceLevelPublic)
					{
						Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Close);
					}
				}
			}
		}

		public new void Dispose()
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Dispose);
			}
			if (m_bClosed)
			{
				return;
			}
			lock (lockXmlStream)
			{
				try
				{
					if (!m_bClosed)
					{
						Close();
					}
				}
				catch (Exception ex)
				{
					OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Dispose, ex);
				}
				finally
				{
					if (ProviderConfig.m_bTraceLevelPublic)
					{
						Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Dispose);
					}
				}
			}
		}

		public override void Flush()
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Flush);
			}
			try
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				throw new NotSupportedException(null, null);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Flush);
				}
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Read);
			}
			try
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				if (count == 0)
				{
					return 0;
				}
				if (offset < 0)
				{
					throw new ArgumentOutOfRangeException("offset");
				}
				if (count < 0)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				if (offset + count > buffer.Length)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				return m_xmlStreamImpl.Read(buffer, offset, count, ref m_position);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Read, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Read);
				}
			}
		}

		public int Read(char[] buffer, int offset, int count)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Read, "OracleXmlStream::Read(char[], int, int)");
			}
			try
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				if (count == 0)
				{
					return 0;
				}
				if (offset < 0)
				{
					throw new ArgumentOutOfRangeException("offset");
				}
				if (count < 0)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				if (offset + count > buffer.Length)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				if (m_position % 2 != 0L)
				{
					throw new ArgumentOutOfRangeException(null, OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.EVEN_VALUE_PARAM_REQUIRED));
				}
				return m_xmlStreamImpl.Read(buffer, offset, count, ref m_position);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Read, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Read);
				}
			}
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Seek);
			}
			try
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				if (origin == SeekOrigin.Begin)
				{
					m_position = offset;
				}
				if (origin == SeekOrigin.Current)
				{
					m_position += offset;
				}
				if (origin == SeekOrigin.End)
				{
					m_position = Length + offset;
				}
				return m_position;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Seek, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Seek);
				}
			}
		}

		public override void SetLength(long newLength)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.SetLength);
			}
			try
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				throw new NotSupportedException(null, null);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.SetLength, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.SetLength);
				}
			}
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Write);
			}
			try
			{
				if (m_bClosed)
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.OBJECT_CLOSED));
				}
				throw new NotSupportedException(null, null);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Write, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.Write);
				}
			}
		}

		~OracleXmlStream()
		{
			Dispose();
		}

		internal void ConnectionClose()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.ConnectionClose);
			}
			try
			{
				if (!m_bClosed)
				{
					Close();
				}
				m_bClosed = true;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, OracleTraceTag.Error, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.ConnectionClose, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleXmlStream, OracleTraceFuncName.ConnectionClose);
				}
			}
		}
	}
}
